package org.example.config.i18nconfig;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 国际化反向翻译工具类
 *
 * 用于解决查询场景中的反向翻译问题：
 * - 用户在前端看到翻译后的文本（如："Change Tag"）
 * - 用户输入翻译后的文本进行搜索
 * - 需要将其转换回数据库中的原始中文（如："修改标签"）进行查询
 * - 支持模糊搜索和片段翻译映射
 *
 * @author system
 * @since 2024-01-15
 */
@Slf4j
@Component
public class I18nReverseTranslateUtils {

    // 支持的语言列表
    private static final List<Locale> SUPPORTED_LOCALES = Arrays.asList(
            Locale.CHINA,           // zh_CN
            Locale.US,              // en_US
            Locale.TRADITIONAL_CHINESE, // zh_TW
            Locale.JAPAN,           // ja_JP
            Locale.KOREA            // ko_KR
    );
    // 模糊搜索相关配置
    private static final int MIN_FUZZY_MATCH_LENGTH = 2;  // 最小模糊匹配长度
    private static final int MAX_FUZZY_RESULTS = 10;  // 最大模糊搜索结果数
    // 缓存反向翻译映射，提高查询性能
    private final Map<String, Map<String, String>> reverseTranslationCache = new ConcurrentHashMap<>();
    // 模糊匹配缓存：locale -> (fragment -> longestCommonSubstring)
    private final Map<String, Map<String, String>> fuzzyMatchCache = new ConcurrentHashMap<>();
    @Autowired
    private MessageSource messageSource;

    @Autowired(required = false)
    private List<I18nProvider> i18nProvider;

    /**
     * 获取所有可能的中文键
     * TODO: 这里可以从数据库动态获取，或者从配置文件读取
     */
    private List<String> getAllPossibleChineseKeys() {
        List<String> res = Optional.ofNullable(i18nProvider)
                .orElse(Collections.emptyList())
                .parallelStream() // 使用并行流提高处理效率
                .filter(Objects::nonNull)
                .map(I18nProvider::getI18nList)
                .filter(list -> !list.isEmpty())
                .flatMap(List::stream)
                .filter(key -> key != null && !key.trim().isEmpty())
                .distinct()
                .collect(Collectors.toList());
        log.info("所有可能的中文键：{}", res);
        return res;
    }

    /**
     * 将用户输入的多语言文本转换为数据库中的中文原文
     * 支持精确匹配和模糊搜索
     *
     * @param userInput 用户输入的文本（可能是任何语言）
     * @return 对应的中文原文，如果找不到则返回原输入
     */
    public String reverseTranslate(String userInput) {
        if (userInput == null || userInput.trim().isEmpty()) {
            return userInput;
        }

        String trimmedInput = userInput.trim();

        // 如果输入本身就是中文，直接返回
        if (isChineseText(trimmedInput)) {
            return trimmedInput;
        }

        // 首先尝试精确反向翻译
        String chineseKey = findChineseKeyByTranslation(trimmedInput);
        if (chineseKey != null) {
            log.debug("精确反向翻译成功: {} -> {}", userInput, chineseKey);
            return chineseKey;
        }

        // 如果精确匹配失败，尝试模糊搜索
        String fuzzyResults = fuzzySearch(trimmedInput);
        if (fuzzyResults != null) {
            // 返回结果
            log.debug("模糊反向翻译成功: {} -> {}", userInput, fuzzyResults);
            return fuzzyResults;
        }

        // 找不到对应翻译，返回原输入
        log.debug("未找到反向翻译: {}", userInput);
        return trimmedInput;
    }

    /**
     * 批量反向翻译
     *
     * @param userInputs 用户输入的文本列表
     * @return 对应的中文原文列表
     */
    public List<String> reverseTranslateBatch(List<String> userInputs) {
        if (userInputs == null || userInputs.isEmpty()) {
            return userInputs;
        }

        return userInputs.stream()
                .map(this::reverseTranslate)
                .collect(Collectors.toList());
    }

    /**
     * 为查询条件进行智能反向翻译
     * 支持模糊匹配场景和片段翻译
     *
     * @param queryText 查询文本
     * @return 包含原文和可能翻译的查询条件列表
     */
    public List<String> getQueryConditions(String queryText) {
        if (queryText == null || queryText.trim().isEmpty()) {
            return Collections.emptyList();
        }

        Set<String> conditions = new HashSet<>();
        String trimmedQuery = queryText.trim();

        // 添加原始输入
        conditions.add(trimmedQuery);

        // 添加精确反向翻译结果
        String chineseKey = reverseTranslate(trimmedQuery);
        if (!chineseKey.equals(trimmedQuery)) {
            conditions.add(chineseKey);
        }

        // 如果是中文，添加所有语言的翻译结果（用于支持多语言模糊搜索）
        if (isChineseText(trimmedQuery)) {
            for (Locale locale : SUPPORTED_LOCALES) {
                try {
                    String translation = messageSource.getMessage(trimmedQuery, null, trimmedQuery, locale);
                    if (!translation.equals(trimmedQuery)) {
                        conditions.add(translation);
                    }
                } catch (Exception e) {
                    // 忽略翻译失败的情况
                }
            }
        }

        return new ArrayList<>(conditions);
    }

    /**
     * 模糊搜索功能
     * 支持片段匹配和相似度计算
     *
     * @param searchText 搜索文本
     * @return 匹配的中文键
     */
    public String fuzzySearch(String searchText) {
        if (searchText == null || searchText.trim().isEmpty() ||
                searchText.length() < MIN_FUZZY_MATCH_LENGTH) {
            return null;
        }

        String trimmedSearch = searchText.trim().toLowerCase();
        Locale currentLocale = LocaleContextHolder.getLocale();
        String localeKey = currentLocale.toString();

        // 检查模糊匹配缓存
        Map<String, String> localeFuzzyCache = fuzzyMatchCache.computeIfAbsent(
                localeKey, k -> new ConcurrentHashMap<>()
        );
        if (localeFuzzyCache.containsKey(trimmedSearch)) {
            return localeFuzzyCache.get(trimmedSearch);
        }

        // 检查字典缓存
        Map<String, String> localeCache = reverseTranslationCache.get(localeKey);
        // 构建反向映射缓存
        if (localeCache == null) {
            localeCache = buildReverseTranslationCache(currentLocale);
            reverseTranslationCache.put(localeKey, localeCache);
        }

        // 1. 找出所有包含该片段的翻译文本
        List<String> matchedChineseKeys = localeCache.entrySet().stream()
                .filter(entry -> entry.getKey().toLowerCase().contains(trimmedSearch))
                .map(Map.Entry::getValue)
                .distinct()
                .toList();

        // 2. 处理匹配结果
        String result;
        if (matchedChineseKeys.isEmpty()) {
            List<String> resultSting = matchByEditDistance(trimmedSearch); // 没有匹配结果尝试纠错查找
            if (resultSting.isEmpty()) {
                result = trimmedSearch;
            } else {
                result = resultSting.get(0);
            }
        } else if (matchedChineseKeys.size() == 1) {
            result = matchedChineseKeys.get(0);  // 唯一匹配
        } else {
            // 3. 多个匹配时寻找最长公共子串
            result = findLongestCommonSubstring(new ArrayList<>(matchedChineseKeys));
        }
        // 更新缓存
        localeFuzzyCache.put(trimmedSearch, result);
        return result;
    }

    /**
     * 编辑距离匹配（用于处理拼写错误）
     */
    public List<String> matchByEditDistance(String trimmedSearch) {
        Locale currentLocale = LocaleContextHolder.getLocale();
        String localeKey = currentLocale.toString();
        Map<String, String> localeCache = reverseTranslationCache.get(localeKey);

        List<FuzzyMatchResult> results = new ArrayList<>();
        for (Map.Entry<String, String> entry : localeCache.entrySet()) {
            String translation = entry.getKey();
            String chineseKey = entry.getValue();
            double similarity = calculateEditDistanceSimilarity(trimmedSearch, translation.toLowerCase());
            results.add(new FuzzyMatchResult(chineseKey, similarity));
        }

        // 按相似度排序并返回结果
        return results.stream()
                .sorted((a, b) -> Double.compare(b.similarity, a.similarity))
                .limit(MAX_FUZZY_RESULTS)
                .map(result -> result.chineseKey)
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 从多个中文键中寻找最长公共子串
     */
    private String findLongestCommonSubstring(List<String> chineseKeys) {
        if (chineseKeys.isEmpty()) return "";
        if (chineseKeys.size() == 1) return chineseKeys.get(0);

        String shortest = chineseKeys.get(0);
        String longestCommon = "";

        // 寻找最长公共子串
        for (int start = 0; start < shortest.length(); start++) {
            for (int end = shortest.length(); end > start + longestCommon.length(); end--) {
                String candidate = shortest.substring(start, end);
                boolean isCommon = true;

                for (int i = 1; i < chineseKeys.size(); i++) {
                    if (!chineseKeys.get(i).contains(candidate)) {
                        isCommon = false;
                        break;
                    }
                }

                if (isCommon && candidate.length() > longestCommon.length()) {
                    longestCommon = candidate;
                }
            }
        }

        return longestCommon;
    }

    /**
     * 计算字符串相似度（基于公共子序列）
     */
    private double calculateSimilarity(String str1, String str2) {
        if (str1.equals(str2)) {
            return 1.0;
        }

        int commonLength = 0;
        int i = 0, j = 0;

        while (i < str1.length() && j < str2.length()) {
            if (str1.charAt(i) == str2.charAt(j)) {
                commonLength++;
                i++;
                j++;
            } else if (str1.length() > str2.length()) {
                i++;
            } else {
                j++;
            }
        }

        return (double) commonLength / Math.max(str1.length(), str2.length());
    }

    /**
     * 基于编辑距离计算相似度
     */
    private double calculateEditDistanceSimilarity(String str1, String str2) {
        int editDistance = calculateEditDistance(str1, str2);
        int maxLength = Math.max(str1.length(), str2.length());
        return maxLength == 0 ? 1.0 : (double) (maxLength - editDistance) / maxLength;
    }

    /**
     * 计算编辑距离（Levenshtein距离）
     */
    private int calculateEditDistance(String str1, String str2) {
        int[][] dp = new int[str1.length() + 1][str2.length() + 1];

        for (int i = 0; i <= str1.length(); i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= str2.length(); j++) {
            dp[0][j] = j;
        }

        for (int i = 1; i <= str1.length(); i++) {
            for (int j = 1; j <= str2.length(); j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
                }
            }
        }

        return dp[str1.length()][str2.length()];
    }

    /**
     * 通过翻译文本查找对应的中文键
     */
    private String findChineseKeyByTranslation(String translation) {
        Locale currentLocale = LocaleContextHolder.getLocale();
        String localeKey = currentLocale.toString();

        // 检查缓存
        Map<String, String> localeCache = reverseTranslationCache.get(localeKey);
        if (localeCache != null && localeCache.containsKey(translation)) {
            return localeCache.get(translation);
        }

        // 构建反向映射缓存
        if (localeCache == null) {
            localeCache = buildReverseTranslationCache(currentLocale);
            reverseTranslationCache.put(localeKey, localeCache);
        }

        return localeCache.get(translation);
    }

    /**
     * 构建指定语言的反向翻译缓存
     */
    private Map<String, String> buildReverseTranslationCache(Locale locale) {
        Map<String, String> cache = new ConcurrentHashMap<>();

        // 获取所有可能的中文键（这里需要根据实际业务场景扩展）
        List<String> chineseKeys = getAllPossibleChineseKeys();

        for (String chineseKey : chineseKeys) {
            try {
                String translation = messageSource.getMessage(chineseKey, null, chineseKey, locale);
                if (!translation.equals(chineseKey)) {
                    cache.put(translation, chineseKey);
                }
            } catch (Exception e) {
                log.debug("获取翻译失败: key={}, locale={}", chineseKey, locale);
            }
        }

        log.info("构建反向翻译缓存完成: locale={}, size={}", locale, cache.size());
        return cache;
    }


    /**
     * 判断文本是否为中文
     */
    private boolean isChineseText(String text) {
        if (text == null || text.isEmpty()) {
            return false;
        }

        // 中文字符范围的正则表达式
        Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
        return chinesePattern.matcher(text).find();
    }

    /**
     * 清空反向翻译缓存（用于重新加载配置时）
     */
    public void clearCache() {
        reverseTranslationCache.clear();
        fuzzyMatchCache.clear();
        log.info("反向翻译缓存和模糊搜索索引已清空");
    }

    /**
     * 获取缓存统计信息
     */
    public Map<String, Object> getCacheStats() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("cache_size", reverseTranslationCache.size());
        stats.put("fuzzy_cache_size", fuzzyMatchCache.size());
        stats.put("supported_locales", SUPPORTED_LOCALES.stream().map(Locale::toString).collect(Collectors.toList()));

        Map<String, Integer> localeCacheSizes = new HashMap<>();
        reverseTranslationCache.forEach((locale, cache) ->
                localeCacheSizes.put(locale, cache.size()));
        stats.put("locale_cache_sizes", localeCacheSizes);

        Map<String, Integer> fuzzyIndexSizes = new HashMap<>();
        fuzzyMatchCache.forEach((locale, index) ->
                fuzzyIndexSizes.put(locale, index.size()));
        stats.put("fuzzy_index_sizes", fuzzyIndexSizes);

        return stats;
    }

    /**
     * 预热缓存（应用启动时调用）
     */
    public void warmUpCache() {
        log.info("开始预热反向翻译缓存...");
        for (Locale locale : SUPPORTED_LOCALES) {
            reverseTranslationCache.put(locale.toString(), buildReverseTranslationCache(locale));
        }
        log.info("反向翻译缓存和模糊搜索索引预热完成");
    }

    /**
     * 模糊匹配结果类
     */
    private static class FuzzyMatchResult {

        final String chineseKey;
        final double similarity;

        FuzzyMatchResult(String chineseKey, double similarity) {
            this.chineseKey = chineseKey;
            this.similarity = similarity;
        }
    }
}